﻿// Almost initial version of Battle Pet / Battle Journal API
// Some of methods may throw exception as result of incorrect call
// So if you found any errors, did any changes or add some remarks  - just let me know

using System;
using Styx.WoWInternals;

namespace PetBuddy.Helpers
{
    
    public static class PetConsts
    {
        // Strings Variables
        public const int LE_BATTLE_PET_ALLY = 1;
        public const int LE_BATTLE_PET_ENEMY = 2;
        public const int LE_BATTLE_PET_WEATHER = 0;
        public const int BATTLE_PET_ABILITY_SWITCH = 4;
        public const int BATTLE_PET_ABILITY_CATCH = 5;
        public const string PET_BATTLE_PAD_INDEX = "PET_BATTLE_PAD_INDEX";

        //Icons
        public const string UNKNOWN_ICON = "Interface\\Icons\\INV_Misc_QuestionMark";
        public const string ABILITY_STRONG = "Interface\\PetBattles\\BattleBar-AbilityBadge-Strong";
        public const string ABILITY_WEAK = "Interface\\PetBattles\\BattleBar-AbilityBadge-Weak";

        //PetTypeStrings
        public const string BATTLE_PET_NAME_1 = "Humanoid";
        public const string BATTLE_PET_NAME_2 = "Dragonkin";
        public const string BATTLE_PET_NAME_3 = "Flying";
        public const string BATTLE_PET_NAME_4 = "Undead";
        public const string BATTLE_PET_NAME_5 = "Critter";
        public const string BATTLE_PET_NAME_6 = "Magic";
        public const string BATTLE_PET_NAME_7 = "Elemental";
        public const string BATTLE_PET_NAME_8 = "Beast";
        public const string BATTLE_PET_NAME_9 = "Aquatic";
        public const string BATTLE_PET_NAME_10 = "Mechanical";

        //PetSourceNames
        public const string BATTLE_PET_SOURCE_1 = "Drop";
        public const string BATTLE_PET_SOURCE_2 = "Quest";
        public const string BATTLE_PET_SOURCE_3 = "Vendor";
        public const string BATTLE_PET_SOURCE_4 = "Profession";
        public const string BATTLE_PET_SOURCE_5 = "Pet Battle";
        public const string BATTLE_PET_SOURCE_6 = "Achievement";
        public const string BATTLE_PET_SOURCE_7 = "World Event";
        public const string BATTLE_PET_SOURCE_8 = "Promotion";
        public const string BATTLE_PET_SOURCE_9 = "Trading Card Game";
        public const string BATTLE_PET_SOURCE_10 = "Blizzard Pet Store";

        //PetJournalBasicFilterFlags
        public const int LE_PET_JOURNAL_FLAG_COLLECTED = 65536;
        public const int LE_PET_JOURNAL_FLAG_NOT_COLLECTED = 131072;
        public const int LE_PET_JOURNAL_FLAG_FAVORITES = 262144;

        public enum PetSortFlags
        {
            LE_SORT_BY_NAME = 1,
            LE_SORT_BY_LEVEL = 2,
            LE_SORT_BY_RARITY = 3,
            LE_SORT_BY_PETTYPE = 4
        }

        [Flags]
        public enum BattleStates
        {
            NOT_IN_COMBAT = 0,
            LE_PET_BATTLE_STATE_CREATED = 1,
            LE_PET_BATTLE_STATE_WAITING_PRE_BATTLE = 2,
            LE_PET_BATTLE_STATE_ROUND_IN_PROGRESS = 3,
            LE_PET_BATTLE_STATE_WAITING_FOR_ROUND_PLAYBACK = 4,
            LE_PET_BATTLE_STATE_WAITING_FOR_FRONT_PETS = 5,
            LE_PET_BATTLE_STATE_CREATED_FAILED = 6,
            LE_PET_BATTLE_STATE_FINAL_ROUND = 7,
            LE_PET_BATTLE_STATE_FINISHED = 8,
            LE_PET_BATTLE_STATE_UNKNOWN = 9
        }

        public enum BattleEvents
        {
            PET_BATTLE_EVENT_ON_APPLY = 0,
            PET_BATTLE_EVENT_ON_DAMAGE_TAKEN = 1,
            PET_BATTLE_EVENT_ON_DAMAGE_DEALT = 2,
            PET_BATTLE_EVENT_ON_HEAL_TAKEN = 3,
            PET_BATTLE_EVENT_ON_HEAL_DEALT = 4,
            PET_BATTLE_EVENT_ON_AURA_REMOVED = 5,
            PET_BATTLE_EVENT_ON_ROUND_START = 6,
            PET_BATTLE_EVENT_ON_ROUND_END = 7,
            PET_BATTLE_EVENT_ON_TURN = 8,
            PET_BATTLE_EVENT_ON_ABILITY = 9,
            PET_BATTLE_EVENT_ON_SWAP_IN = 10,
            PET_BATTLE_EVENT_ON_SWAP_OUT = 11,
        }

        public enum PetActionType
        {
            LE_BATTLE_PET_ACTION_NONE = 1,
            LE_BATTLE_PET_ACTION_ABILITY = 2,
            LE_BATTLE_PET_ACTION_SWITCH_PET = 3,
            LE_BATTLE_PET_ACTION_TRAP = 4,
            LE_BATTLE_PET_ACTION_SKIP = 5
        }

        public enum PetBattleStat
        {
            PET_BATTLE_STATE_ATTACK = 18,
            PET_BATTLE_STATE_SPEED = 20
        }

        public enum Rarity
        {
            Poor = 0,
            Common = 1,
            Uncommon = 2,
            Rare = 3,
            Epic = 4,
            Legendary = 5,
            Artifact = 6,
            Heirloom = 7
        }
    }

    public static class PetBattles
    {

        #region Data structs

        public struct _AbilityEffect
        {
            public int points;
            public int accuracy;
            public int duration;
        }

        public struct _AbilityInfo
        {
            public int id;
            public string name;
            public string icon;
            public int maxCooldown;
            public string unparsedDescription;
            public int numTurns;
            public int petType;
            public int StrongWeakHints;
        }

        public struct _AbilityState
        {
            public bool isUsable;
            public int currentCooldown;
        }

        public struct _AuraInfo
        {
            public int id ;
            public int instanceID ;
            public int turnsRemaining ;
            public bool isBuff ;
        }

        public struct _SelectedAction
        {
            public PetConsts.PetActionType ActionType;
            public int ActionIndex;
        }

        public struct _TurnTiming
        {
            public long timeRemaining ;
            public long turnTime ;
        }

        public struct _PetXP
        {
            public int xp;
            public int maxXp;
        }

        public enum PVPqueueState
        {
            queued,
            proposal,
            suspended
        }

        #endregion


        #region Util functions

        private static bool InRange<T>( this T value, T from, T to ) where T : IComparable<T>
        {
            return value.CompareTo( from ) >= 0 && value.CompareTo( to ) <= 0;
        }

        private static bool OutOfRange<T>( this T value, T from, T to ) where T : IComparable<T>
        {
            return value.CompareTo( from ) <= 0 && value.CompareTo( to ) >= 0;
        }

        private static bool ToBoolean(string value) { return (value != "nil" & value != "0") | value == "true"; }
        
        #endregion


        #region API

        /// <summary>
        /// Accept PVP duel request
        /// </summary>
        /// 
        public static void AcceptPVPDuel()
        {
            Lua.DoString( "return C_PetBattles.AcceptPVPDuel()" );
        }


        /// <summary>
        /// Accept Battle queue propose match
        /// </summary>
        /// 
        public static void AcceptPVPQueuedMatch()
        {
            Lua.DoString("return C_PetBattles.AcceptQueuedPVPMatch()");
        }
        

        /// <summary>
        /// Decline PVP duel request
        /// </summary>
        /// 
        public static void CancelPVPDuel()
        {
            Lua.DoString( "return C_PetBattles.CancelPVPDuel()" );
        }


        /// <summary>
        /// Is active pet can be changed
        /// </summary>
        /// <returns>(bool) can change</returns>
        /// 
        public static bool CanActivePetSwapOut()
        {
            return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.CanActivePetSwapOut()", 0));
        }


        /// <summary>
        /// Is pet can be call in battle
        /// </summary>
        /// <param name="petLOIndx">(int) pet LoadOut index</param>
        /// <returns>(bool) can be called</returns>
        /// 
        public static bool CanPetSwapIn(int petLOIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetBattles.CanPetSwapIn({0})", petLOIndx), 0));
        }


        /// <summary>
        /// Change pet on another in party (fail safe)
        /// </summary>
        /// <param name="petIndex">order of pet (start with 1 to 3)</param>
        /// 
        public static void ChangePet(int petIndex = 1)
        {
            var _curPet = GetActivePet();
            if ( _curPet != petIndex )
            {
                Lua.DoString( string.Format( "return C_PetBattles.ChangePet({0})", petIndex ) );
            }
            else
                PetBuddy.dlog( "ChangePet", "Can't change pet on himself", null );
        }


        /// <summary>
        /// Decline Battle queue propose match
        /// </summary>
        /// 
        public static void DeclineQueuedPVPMatch()
        {
            Lua.DoString("return C_PetBattles.DeclineQueuedPVPMatch()");
        }


        /// <summary>
        /// Leave current match (Give up)
        /// </summary>
        /// 
        public static void LeaveGame()
        {
            Lua.DoString( "return C_PetBattles.ForfeitGame()" );
        }


        /// <summary>
        /// Return Info about ability effect (Unknown usage)
        /// </summary>
        /// <param name="abilityID"></param>
        /// <param name="turnIndex"></param>
        /// <param name="effectIndex"></param>
        /// <returns>(_AbilityEffect) {points, accuracy, duration}</returns>
        /// 
        public static _AbilityEffect GetAbilityEffectInfo( int abilityID, int turnIndex, int effectIndex )
        {
            var _retValues = Lua.GetReturnValues( string.Format("return C_PetBattles.GetAbilityEffectInfo({0},{1},{2})", abilityID, turnIndex, effectIndex) );
            var retValues = new _AbilityEffect
                                {
                                    points = Convert.ToInt32(_retValues[0]),
                                    accuracy = Convert.ToInt32(_retValues[1]),
                                    duration = Convert.ToInt32(_retValues[2])
                                };
            return retValues;
        }


        /// <summary>
        /// Return info about pet ability
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <param name="abilityIndex">Index of pet ability (1-3)</param>
        /// <returns>(AbilityInfo) {id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints}</returns>
        /// <remarks>Useble only in battle</remarks>
        /// 
        public static _AbilityInfo GetAbilityInfo(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1, int abilityIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            if (!abilityIndex.InRange(1, 3)) abilityIndex = 1;

            var _retValues = Lua.GetReturnValues(string.Format("return C_PetBattles.GetAbilityInfo({0},{1},{2})", petOwner, petIndex, abilityIndex));

            if (_retValues[2] == null || _retValues[2].Length < 3)
                _retValues[2] = PetConsts.UNKNOWN_ICON;

            var retVal = new _AbilityInfo
                             {
                                 id = Convert.ToInt32(_retValues[0]),
                                 name = _retValues[1],
                                 icon = _retValues[2],
                                 maxCooldown = Convert.ToInt32(_retValues[3]),
                                 unparsedDescription = _retValues[4],
                                 numTurns = Convert.ToInt32(_retValues[5]),
                                 petType = Convert.ToInt32(_retValues[6]),
                                 StrongWeakHints = GetAttackModifier(Convert.ToInt32(_retValues[6]), GetPetType(2, GetActivePet(2)))
                             };
            return retVal;
        }


        /// <summary>
        /// Return info about pet ability
        /// </summary>
        /// <param name="abilityID">Ability ID</param>
        /// <returns>(AbilityInfo) {id, name, icon, maxCooldown, unparsedDescription, numTurns, petType, noStrongWeakHints}</returns>
        /// <remarks>Useble only in battle</remarks>
        /// 
        public static _AbilityInfo GetAbilityInfoByID( int abilityID )
        {

            var _retValues = Lua.GetReturnValues(string.Format("return C_PetBattles.GetAbilityInfoByID({0})", abilityID));

            if (_retValues[2] == null || _retValues[2].Length < 3)
                _retValues[2] = PetConsts.UNKNOWN_ICON;

            var retVal = new _AbilityInfo
                             {
                                 id = Convert.ToInt32(_retValues[0]),
                                 name = _retValues[1],
                                 icon = _retValues[2],
                                 maxCooldown = Convert.ToInt32(_retValues[3]),
                                 unparsedDescription = _retValues[4],
                                 numTurns = Convert.ToInt32(_retValues[5]),
                                 petType = Convert.ToInt32(_retValues[6]),
                                 StrongWeakHints = GetAttackModifier(Convert.ToInt32(_retValues[6]), GetPetType(2, GetActivePet(2)))
                             };
            return retVal;
        }


        /// <summary>
        /// Return useless data
        /// </summary>
        /// <param name="abilityID"></param>
        /// <param name="procType"></param>
        /// <returns></returns>
        /// 
        public static int GetAbilityProcTurnIndex( int abilityID, object procType )
        {
            var retVal = Lua.GetReturnValues(string.Format("return C_PetBattles.GetAbilityProcTurnIndex({0},{1})", abilityID, procType));
            return Convert.ToInt16( retVal );
        }


        /// <summary>
        /// Return ability state
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <param name="abilityIndex">Index of pet ability (1-3)</param>
        /// <returns>(AbilityState) {(bool)isUsable, (int)currentCooldown}</returns>
        /// 
        public static _AbilityState GetAbilityState(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1, int abilityIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            if (!abilityIndex.InRange(1, 3)) abilityIndex = 1;

            var _retValues = Lua.GetReturnValues( string.Format( "return C_PetBattles.GetAbilityState({0},{1},{2})", petOwner, petIndex, abilityIndex ) );
            var retVal = new _AbilityState
            {
                isUsable = ToBoolean(_retValues[0]),
                currentCooldown = Convert.ToInt32(_retValues[1])
            };
            return retVal;
        }


        /// <summary>
        /// Return ability state modificator
        /// </summary>
        /// <param name="abilityID">(int) ability ID</param>
        /// <param name="stateID">(int) state enum ID</param>
        /// <returns>(string[]) modificators</returns>
        /// 
        public static string[] GetAbilityStateModification(int abilityID, int stateID)
        {
            return Lua.GetReturnValues(string.Format("return C_PetBattles.GetAbilityStateModification({0}, {1})", abilityID, stateID)).ToArray();
        }


        /// <summary>
        /// Return ally or enemy active pet index
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <returns>(int)index</returns>
        /// 
        public static int GetActivePet(int petOwner = PetConsts.LE_BATTLE_PET_ALLY)
        {
            var petIndex = Lua.GetReturnValues( string.Format( "return C_PetBattles.GetActivePet({0})", petOwner ) );
            return petIndex[0] != "nil" ? Convert.ToInt32(petIndex[0]) : 1;
        }


        /// <summary>
        /// Return array of possible effect names
        /// </summary>
        /// <returns>(string[])Names list</returns>
        /// 
        public static string[] GetAllEffectNames()
        {
            return Lua.GetReturnValues("return C_PetBattles.GetAllEffectNames()").ToArray();
        }


        /// <summary>
        /// Return Pet attack modifier (strong/none/weak)
        /// </summary>
        /// <param name="petType">Pet type index</param>
        /// <param name="compareType">Compared pet type index</param>
        /// <returns>[0.66] - weak, [1] - none, [1.5] - strong</returns>
        /// 
        public static int GetAttackModifier(int petType, int compareType)
        {
            if (!petType.InRange(1, 10)) petType = GetPetType(PetConsts.LE_BATTLE_PET_ALLY, GetActivePet());
            if (!compareType.InRange(1, 10)) compareType = GetPetType(PetConsts.LE_BATTLE_PET_ENEMY, GetActivePet(PetConsts.LE_BATTLE_PET_ENEMY));

            var _retValues = Lua.GetReturnValues(string.Format("return C_PetBattles.GetAttackModifier({0},{1})", petType, compareType));
            return _retValues[0] != "nil" ? Convert.ToInt32(_retValues[0]) : 1;
        }
        

        /// <summary>
        /// Return info about Aura of pet
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <param name="auraID">AuraID</param>
        /// <returns>(_AuraInfo) {(int)id, (int)instanceID, (int)turnsRemaining, (bool)isBuff}</returns>
        /// 
        public static _AuraInfo GetAuraInfo(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1, int auraID = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            if (auraID.OutOfRange(1, 9999)) auraID = 1;
            var _retValues =
                Lua.GetReturnValues(string.Format("return C_PetBattles.GetAuraInfo({0},{1},{2})", petOwner, petIndex, auraID));
            var retVal = new _AuraInfo
                             {
                                 id = Convert.ToInt32(_retValues[0]),
                                 instanceID = Convert.ToInt32(_retValues[1]),
                                 turnsRemaining = Convert.ToInt32(_retValues[2]),
                                 isBuff = ToBoolean(_retValues[6])
                             };
            return retVal;
        }


        /// <summary>
        /// Return BattlePet link
        /// </summary>
        /// <param name="id">(int) pet id</param>
        /// <returns>(string) link</returns>
        /// 
        public static string GetBattlePetLink(int id)
        {
            return Lua.GetReturnVal<string>(string.Format("return C_PetJournal.GetBattlePetLink({0})", id), 0);
        }


        /// <summary>
        /// Return PetBattle progress state
        /// </summary>
        /// <returns>(PetBattleStates)state</returns>
        /// 
        public static PetConsts.BattleStates GetBattleState
        {
            get
            {
                var _retValue = Lua.GetReturnVal<string>("return C_PetBattles.GetBattleState()", 0);
                var retVal = Convert.ToInt32(_retValue);
                return (PetConsts.BattleStates) (retVal.InRange(1, 8) ? retVal : 9);
            }
        }


        /// <summary>
        /// Return quality of pet ([1]-Poor, [2]-White, [3]-Common,[4]-Rare,[5]-Epique,[6]-Legen...wait for it...dary
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(int)quality</returns>
        /// 
        public static int GetBreedQuality(int petOwner = PetConsts.LE_BATTLE_PET_ENEMY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(PetConsts.LE_BATTLE_PET_ENEMY);
            var _retValue = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetBreedQuality({0},{1})", petOwner, petIndex), 0);
            var retVal = Convert.ToInt32(_retValue);
            return retVal.InRange(1, 6) ? retVal : 1;
        }


        /// <summary>
        /// Return ID of current display
        /// </summary>
        /// <returns>(int)ID</returns>
        /// 
        public static int GetDisplayID
        {
            get
            {
                var retVal = Lua.GetReturnVal<string>("return C_PetBattles.GetDisplayID()", 0);
                return Convert.ToInt32(retVal);
            }
        }


        /// <summary>
        /// Return Health of Pet
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(int)Health</returns>
        /// 
        public static int GetHealth(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            var retVal = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetHealth({0},{1})", petOwner, petIndex), 0);
            return retVal != "nil" ? int.Parse(retVal) : 0;
        }


        /// <summary>
        /// Return an Icon of Pet
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(string)path</returns>
        /// 
        public static string GetIcon(int petOwner = PetConsts.LE_BATTLE_PET_ENEMY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(PetConsts.LE_BATTLE_PET_ENEMY);
            var retVal = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetIcon({0},{1})", petOwner, petIndex), 0);
            return retVal ?? PetConsts.UNKNOWN_ICON;
        }


        /// <summary>
        /// Return level of pet
        /// </summary>
        /// <param name="petOwner">(PetSideEnum) ally or enemy flag</param>
        /// <param name="petIndex">Pet index (1-3)</param>
        /// <returns>(int)Level</returns>
        /// 
        public static int GetLevel(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet();
            var retVal = Lua.GetReturnValues(string.Format("return C_PetBattles.GetLevel({0},{1})", petOwner, petIndex));
            return retVal[0] != "nil" ? Convert.ToInt32(retVal[0]) : 1;
        }


        /// <summary>
        /// Return Max Health of Pet
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(int)Max_health</returns>
        /// 
        public static int GetMaxHealth(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            var retVal = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetMaxHealth({0},{1})", petOwner, petIndex), 0);
            return Convert.ToInt32(retVal);
        }


        /// <summary>
        /// Return Name of Pet
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(string)Name</returns>
        /// 
        public static string GetName(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            var retVal = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetName({0},{1})", petOwner, petIndex), 0);
            return retVal ?? "UNKNONW";
        }


        /// <summary>
        /// Return number of Pets Auras
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(int)count</returns>
        /// 
        public static int GetNumAuras(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            var retVal = Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetNumAuras({0},{1})", petOwner, petIndex), 0);
            return Convert.ToInt32(retVal);
        }


        /// <summary>
        /// Return number of pets player or enemy have
        /// </summary>
        /// <returns>(int)count</returns>
        /// 
        public static int GetNumPets(int petOwner = PetConsts.LE_BATTLE_PET_ALLY)
        {
            return Convert.ToInt32(Lua.GetReturnVal<string>(string.Format("return C_PetBattles.GetNumPets({0})", petOwner), 0));
        }


        /// <summary>
        /// Return ID of pet species
        /// </summary>
        /// <param name="petOwner">Ally or Enemy</param>
        /// <param name="petIndex">Index of pet (1-3)</param>
        /// <returns>(int)ID</returns>
        /// 
        public static int GetPetSpeciesID(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet(petOwner);
            return Convert.ToInt32( Lua.GetReturnVal<string>(
                        string.Format("return C_PetBattles.GetPetSpeciesID({0},{1})", petOwner, petIndex), 0));
        }


        /// <summary>
        /// Return type of pet
        /// </summary>
        /// <param name="petOwner">Pet owner (ally or enemy)</param>
        /// <param name="petIndex">Index of pet</param>
        /// <returns>(int)index</returns>
        /// 
        public static int GetPetType(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet();
            var _retValue = Lua.GetReturnValues( string.Format("return C_PetBattles.GetPetType({0},{1})", petOwner, petIndex) );
            return _retValue[0] != "nil" ? Convert.ToInt32(_retValue[0]) : 1;
        }


        /// <summary>
        /// Return Trap ability ID
        /// </summary>
        /// <returns>(int)ID</returns>
        /// 
        public static int GetPlayerTrapAbility
        {
            get { return Convert.ToInt32(Lua.GetReturnVal<string>("return C_PetBattles.GetPlayerTrapAbility()", 0)); }
        }


        /// <summary>
        /// Return Attack Power of pet
        /// </summary>
        /// <param name="petOwner">Pet owner (ally or enemy)</param>
        /// <param name="petIndex">Index of pet</param>
        /// <returns>(int)APower</returns>
        /// 
        public static int GetPower(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet();
            var _retValue = Lua.GetReturnValues(string.Format("return C_PetBattles.GetPower({0},{1})", petOwner, petIndex));
            return _retValue[0] != "nil" ? Convert.ToInt32(_retValue[0]) : 1;
        }


        /// <summary>
        /// Return state of PVP matchmaking process
        /// </summary>
        /// <returns>enum(PVPqueueState) state</returns>
        /// 
        public static PVPqueueState GetPVPMatchmakingInfo()
        {
            PVPqueueState _retVal;
            Enum.TryParse(Lua.GetReturnVal<string>("return C_PetBattles.GetPVPMatchmakingInfo()", 0), true, out _retVal);
            return _retVal;
        }

        
        /// <summary>
        /// Return current selected action type and selected action slot
        /// </summary>
        /// <returns>(_SelectedAction) {(PetActionType)type, (int)index}</returns>
        /// 
        public static _SelectedAction GetSelectedAction
        {
            get
            {
                var _retValues = Lua.GetReturnValues("return C_PetBattles.GetSelectedAction()");
                var retVal = new _SelectedAction
                                 {
                                     ActionType = (PetConsts.PetActionType) Convert.ToInt32(_retValues[0]),
                                     ActionIndex = Convert.ToInt32(_retValues[1])
                                 };
                return retVal;
            }
        }


        /// <summary>
        /// Return Speed of Pet
        /// </summary>
        /// <param name="petOwner">Pet owner (ally or enemy)</param>
        /// <param name="petIndex">Index of pet</param>
        /// <returns>(int)speed</returns>
        /// 
        public static int GetSpeed(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            if (!petIndex.InRange(1, 3)) petIndex = GetActivePet();
            var _retValue = Lua.GetReturnValues(string.Format("return C_PetBattles.GetSpeed({0},{1})", petOwner, petIndex));
            return _retValue[0] != "nil" ? Convert.ToInt32(_retValue[0]) : 1;
        }

        
        /// <summary>
        /// Return state value of specifed index 
        /// </summary>
        /// <param name="petOwner">Pet owner (ally or enemy)</param>
        /// <param name="petIndex">Index of pet</param>
        /// <param name="stateID">State ID (enum)PetBattleState</param>
        /// <returns>(int)State</returns>
        /// 
        public static int GetStateValue(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1, PetConsts.PetBattleStat stateID = PetConsts.PetBattleStat.PET_BATTLE_STATE_SPEED)
        {
            return Convert.ToInt32(Lua.GetReturnVal<string>(
                        string.Format("return C_PetBattles.GetStateValue({0},{1},{2})", petOwner, petIndex, stateID), 0));
        }

        
        /// <summary>
        /// Return turn timing info
        /// </summary>
        /// <returns>(TurnTiming) {(long)timeRemaining, (long)turnTime}</returns>
        /// 
        public static _TurnTiming GetTurnTimeInfo
        {
            get
            {
                var _retValues = Lua.GetReturnValues("return C_PetBattles.GetTurnTimeInfo()");
                var retVal = new _TurnTiming
                                 {
                                     timeRemaining = Convert.ToInt64(_retValues[0]),
                                     turnTime = Convert.ToInt64(_retValues[1])
                                 };
                return retVal;
            }
        }

        
        /// <summary>
        /// Return Pet XP info
        /// </summary>
        /// <param name="petOwner">Pet owner (ally or enemy)</param>
        /// <param name="petIndex">Index of pet</param>
        /// <returns>(_PetXP) {(int)xp, (int)maxXp}</returns>
        /// 
        public static _PetXP GetXP(int petOwner = PetConsts.LE_BATTLE_PET_ALLY, int petIndex = 1)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetBattles.GetXP({0},{1})", petOwner, petIndex));
            var retVal = new _PetXP
                             {
                                 xp = Convert.ToInt32(_retValues[0]),
                                 maxXp = Convert.ToInt32(_retValues[1])
                             };
            return retVal;
        }

        
        /// <summary>
        /// Return in pet battle status
        /// </summary>
        /// <returns>(bool)in_battle</returns>
        /// 
        public static bool IsInBattle
        {
            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsInBattle()", 0)); }
        }

        
        /// <summary>
        /// Return is target player NPC or not
        /// </summary>
        /// <returns>(bool)isNPC</returns>
        /// 
        public static bool IsPlayerNPC
        {
            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsPlayerNPC(LE_BATTLE_PET_ENEMY)", 0)); }
        }
        

        /// <summary>
        /// Return is availability to use trap
        /// </summary>
        /// <returns>(bool)trap</returns>
        /// 
        public static bool IsTrapAvailable
        {
            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsTrapAvailable()", 0)); }
        }


        /// <summary>
        /// Return is eaiting enemy torn
        /// </summary>
        /// <returns>(bool)waiting</returns>
        /// 
        public static bool IsWaitingOnOpponent
        {

            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsWaitingOnOpponent()", 0)); }
        }


        /// <summary>
        /// Return is wild(outdoor) battle
        /// </summary>
        /// <returns>(bool)wild</returns>
        /// 
        public static bool IsWildBattle
        {

            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsWildBattle()", 0)); }
        }

        
        /// <summary>
        /// Return true if Pet select forced
        /// </summary>
        /// <returns>(bool)select_forced</returns>
        /// 
        public static bool ShouldShowPetSelect
        {

            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.ShouldShowPetSelect()", 0)); }
        }

        
        /// <summary>
        /// Return true if skip turn available
        /// </summary>
        /// <returns>(bool)skip_available</returns>
        /// 
        public static bool IsSkipAvailable
        {

            get { return ToBoolean(Lua.GetReturnVal<string>("return C_PetBattles.IsSkipAvailable()", 0)); }
        }

        
        /// <summary>
        /// Skip turn
        /// </summary>
        /// 
        public static void SkipTurn()
        {
            Lua.DoString("if C_PetBattles.IsSkipAvailable() then C_PetBattles.SkipTurn() end");
        }

        
        /// <summary>
        /// Request PVP Pet dual with unitID
        /// </summary>
        /// <param name="UnitID">(string)UnitID [target,party1..N ect]</param>
        /// 
        public static void StartPVPDuel(string UnitID)
        {
            Lua.DoString(string.Format("C_PetBattles.StartPVPDuel({0}, 1)", UnitID));
        }

        
        /// <summary>
        /// Start Pet Battle matchmaking
        /// </summary>
        /// 
        public static void StartPVPMatchmaking()
        {
            Lua.DoString( "C_PetBattles.StartPVPMatchmaking()" );
        }

        
        /// <summary>
        /// Cancel Pet Battle matchmaking
        /// </summary>
        /// 
        public static void StopPVPMatchmaking()
        {
            Lua.DoString( "C_PetBattles.StopPVPMatchmaking()" );
        }

        
        /// <summary>
        /// Use ability by ID(index)
        /// </summary>
        /// <param name="abilityID">(int)ID/Index</param>
        /// 
        public static void UseAbility(int abilityID)
        {
            Lua.DoString(string.Format("C_PetBattles.UseAbility({0})", abilityID));
        }

        
        /// <summary>
        /// Use Trap
        /// </summary>
        /// 
        public static void UseTrap()
        {
            Lua.DoString( "C_PetBattles.UseTrap()" );
        }

        #endregion
    }

    public static class PetJournal
    {
        #region Journal structs

        public struct _PetJournalCounts
        {
            public int numPets;
            public int numOwned;
        }

        public struct _PetAbilityInfo
        {
            public string name ;
            public string icon ;
            public int petType ;
        }

        public struct _PetAbilityList
        {
            public int[] abilities;
            public int[] levels;
        }

        public struct _PetInfo
        {
            public string petGUID;
            public int speciesID;
            public bool isOwned;
            public string customName;
            public int level;
            public int xp;
            public int maxXp;
            public int displayID;
            public bool favorite;
            public bool isRevoked;
            public string petName;
            public string petIcon;
            public int petType;
            public int creatureID;
            public string sourceText;
            public string description;
            public bool isWildPet;
            public bool canBattle;
            public bool tradable;
            public bool unique;
        }

        public struct _loadOutInfo
        {
            public string petGUID;
            public int ability1ID;
            public int ability2ID;
            public int ability3ID;
            public bool locked;
        }

        public struct _PetStats
        {
            public int health;
            public int maxHealth;
            public int attack;
            public int speed;
            public int rarity;
        }

        public struct _PetCountInfo
        {
            public int numCollected;
            public int limit;
        }

        #endregion


        #region Utils

        /// <summary>
        /// Return array of loadOut locked state of Pet team slots
        /// </summary>
        /// <returns>(bool[3]) lockedState</returns>
        /// 
        public static bool[] GetLoadOutActiveSlots
        {
            get
            {
                var retVal = new bool[3];
                for (int i = 1; i <= 3; i++)
                {
                    retVal[i] = GetPetLoadOutInfo(i).locked;
                }

                return retVal;
            }
        }

        public static string PetIDToGUID(int petID)
        {
            return Lua.GetReturnVal<string>(string.Format("return (\"0x%016x\"):format({0})", petID), 0);
        }
        public static string PetIDToGUID(string petID)
        {
            var intID = Convert.ToInt32(petID);
            return intID > 0 ? PetIDToGUID(intID) : "";
        }

        private static bool ToBoolean(string value) { return (value != "nil" & value != "0") | value == "true"; }

        #endregion


        #region API

        /// <summary>
        /// Mark all Pet source filters
        /// </summary>
        /// 
        public static void AddAllPetSourcesFilter()
        {
            Lua.DoString( "C_PetJournal.AddAllPetSourcesFilter()" );
        }


        /// <summary>
        /// Mark all Pet types filters
        /// </summary>
        /// 
        public static void AddAllPetTypesFilter()
        {
            Lua.DoString( "C_PetJournal.AddAllPetTypesFilter()" );
        }


        /// <summary>
        /// Putting pet by ID in cage
        /// </summary>
        /// <param name="petJournalIndx">(int) Journal Index</param>
        /// <returns>(bool) result</returns>
        /// 
        public static bool CagePetByID(int petJournalIndx)
        {
            if (!PetIsCapturable(petJournalIndx))
                return false;
            Lua.DoString( string.Format("C_PetJournal.CagePetByID({0})", petJournalIndx) );
            return true;
        }


        /// <summary>
        /// UnMark all Pet source filters
        /// </summary>
        /// 
        public static void ClearAllPetSourcesFilter()
        {
            Lua.DoString( "C_PetJournal.ClearAllPetSourcesFilter()" );
        }


        /// <summary>
        /// UnMark all Pet types filters
        /// </summary>
        /// 
        public static void ClearAllPetTypesFilter()
        {
            Lua.DoString( "return C_PetJournal.ClearAllPetTypesFilter()" );
        }


        /// <summary>
        /// Clear Pet journal search filter
        /// </summary>
        /// 
        public static void ClearSearchFilter()
        {
            Lua.DoString( "return C_PetJournal.ClearSearchFilter()" );
        }


        /// <summary>
        /// Return species ID and pet GUID as part of _PetInfo struct
        /// </summary>
        /// <param name="petName">(string) pet name</param>
        /// <returns>(_PetInfo) {speciesID, petGUID}</returns>
        /// 
        public static _PetInfo FindPetGUIDByName(string petName)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.FindPetIDByName('{0}')", petName));
            return new _PetInfo
                       {
                           speciesID    = _retValues[0] != "nil" ? Convert.ToInt32(_retValues[0]) : 0,
                           petGUID      = _retValues[1]         ?? ""
                       };
        }


        /// <summary>
        /// Return collected and max collectable info of pet by species ID
        /// </summary>
        /// <param name="speciesId">(int) species ID</param>
        /// <returns>(_PetCountInfo) {numCollected, limit}</returns>
        /// 
        public static _PetCountInfo GetNumCollectedInfo(int speciesId)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetNumCollectedInfo({0})", speciesId));
            return new _PetCountInfo
                       {
                           numCollected = _retValues[0] != "nil" ? Convert.ToInt32(_retValues[0]) : 0,
                           limit = _retValues[1] != "nil" ? Convert.ToInt32(_retValues[1]) : 0
                       };
        }


        /// <summary>
        /// Return count of possible pet sources
        /// </summary>
        /// <returns>(int) source count</returns>
        /// 
        public static int GetNumPetSources
        {
            get { return Convert.ToInt32(Lua.GetReturnVal<string>("return C_PetJournal.GetNumPetSources()", 0)); }
        }


        /// <summary>
        /// Return count of pet types
        /// </summary>
        /// <returns>(int) types count</returns>
        /// 
        public static int GetNumPetTypes
        {
            get { return Convert.ToInt32(Lua.GetReturnVal<string>("return C_PetJournal.GetNumPetTypes()", 0)); }
        }


        /// <summary>
        /// Returntotal and owned pet count
        /// </summary>
        /// <returns>(_PetJournalCounts) {(int)numPets, (int)numOwned}</returns>
        /// 
        public static _PetJournalCounts GetNumPets
        {
            get
            {
                var isWild = Lua.GetReturnVal<string>("return PetJournal.isWild", 0);
                var _retValues =
                    Lua.GetReturnValues(string.Format("return C_PetJournal.GetNumPets({0})", isWild)).ToArray();
                return new _PetJournalCounts
                           {
                               numPets = Convert.ToInt32(_retValues[0]),
                               numOwned = Convert.ToInt32(_retValues[1])
                           };
            }
        }


        /// <summary>
        /// Returns a string describing how many of the pets of a battle pet species you've collected
        /// </summary>
        /// <param name="speciesId">(int) species ID</param>
        /// <returns>(string) "|cFFFFD200Collected (1/3)", or nil if you haven't collected any</returns>
        /// 
        public static string GetOwnedBattlePetString(int speciesId)
        {
            return Lua.GetReturnVal<string>(string.Format("return C_PetJournal.GetOwnedBattlePetString({0})", speciesId), 0);
        }


        /// <summary>
        /// Return info about Pet ability by index (1-6)
        /// </summary>
        /// <param name="abilityID"></param>
        /// <returns></returns>
        /// 
        public static _PetAbilityInfo GetPetAbilityInfo(int abilityID)
        {
            var _retValues = Lua.GetReturnValues( string.Format("return C_PetJournal.GetPetAbilityInfo({0})", abilityID) );
            return new _PetAbilityInfo
                       {
                           name = _retValues[0],
                           icon = _retValues[1],
                           petType = Convert.ToInt32(_retValues[2])
                       };
        }


        /// <summary>
        /// Return arrays with ability ID's and array of lvl on which they activates
        /// </summary>
        /// <param name="speciesID">(int) Pet species</param>
        /// <returns>(_PetAbilityList) {(int[6])abilities, (int[6])levels}</returns>
        /// 
        public static _PetAbilityList GetPetAbilityList(int speciesID)
        {
            var _retValues = Lua.GetReturnValues(string.Format("local a,b = C_PetJournal.GetPetAbilityList({0}); return a[1],a[2],a[3],a[4],a[5],a[6],b[1],b[2],b[3],b[4],b[5],b[6]", speciesID)).ToArray();
            return new _PetAbilityList
                       {
                           abilities = new[]
                                        {
                                            Convert.ToInt32(_retValues[0]),
                                            Convert.ToInt32(_retValues[1]),
                                            Convert.ToInt32(_retValues[2]),
                                            Convert.ToInt32(_retValues[3]),
                                            Convert.ToInt32(_retValues[4]),
                                            Convert.ToInt32(_retValues[5])
                                        },
                           levels = new[]
                                        {
                                            Convert.ToInt32(_retValues[6]),
                                            Convert.ToInt32(_retValues[7]),
                                            Convert.ToInt32(_retValues[8]),
                                            Convert.ToInt32(_retValues[9]),
                                            Convert.ToInt32(_retValues[10]),
                                            Convert.ToInt32(_retValues[11])
                                        }
                       };
        }


        /// <summary>
        /// Return inf about Pet by index
        /// </summary>
        /// <param name="index"></param>
        /// <param name="isWild"></param>
        /// <returns>(_PetInfo) {(string)petGUID, (int)speciesID, (bool)isOwned, (string)customName, (int)level, (bool)favorite, (bool)isRevoked, (string)name, (string)icon, (int)petType, (int)creatureID, (string)sourceText, (string)description, (bool)isWildPet, (bool)unknown_1, (bool)unknown_2, (bool)unknown_3}}</returns>
        public static _PetInfo GetPetInfoByIndex(int index, bool isWild = false)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetPetInfoByIndex({0},{1})", index, isWild));
            return new _PetInfo
                       {
                           petGUID      = _retValues[0]          ?? "",
                           speciesID    = _retValues[1]  != "nil" ? Convert.ToInt32(_retValues[1]) : 0,
                           isOwned      = _retValues[2]  != "nil" && ToBoolean(_retValues[2]),     
                           customName   = _retValues[3]          ?? "",
                           level        = _retValues[4]  != "nil" ? Convert.ToInt32(_retValues[4]) : 0,
                           favorite     = _retValues[5]  != "nil" && ToBoolean(_retValues[5]),     
                           isRevoked    = _retValues[6]  != "nil" && ToBoolean(_retValues[6]),     
                           petName      = _retValues[7]          ?? "",
                           petIcon      = _retValues[8]          ?? PetConsts.UNKNOWN_ICON,       
                           petType      = _retValues[9]  != "nil" ? Convert.ToInt32(_retValues[9]) : 0,
                           creatureID   = _retValues[10] != "nil" ? Convert.ToInt32(_retValues[10]) : 0,
                           sourceText   = _retValues[11]         ?? "",
                           description  = _retValues[12]         ?? "",
                           isWildPet    = _retValues[13] != "nil" && ToBoolean(_retValues[13]),
                           canBattle    = _retValues[14] != "nil" && ToBoolean(_retValues[14]),
                           tradable     = _retValues[15] != "nil" && ToBoolean(_retValues[15]),
                           unique       = _retValues[16] != "nil" && ToBoolean(_retValues[16])
                       };
        }


        /// <summary>
        /// Return pet info by petGUID
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// <returns>[_PetInfo] {(int)speciesID, (string)customName, (int)level, (int)xp, (int)maxXp, (int)displayID, ()petName, ()petIcon, (int)petType, (int)creatureID, (string)sourceText, (string)description, (bool)isWildPet, (bool)unknown_1, (bool)unknown_2, (bool)unknown_3}</returns>
        /// 
        public static _PetInfo GetPetInfoByPetGUID(string petGUID)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetPetInfoByPetID('{0}')", petGUID));
            return new _PetInfo
                        {
                            speciesID   = _retValues[0]  != "nil" ? Convert.ToInt32(_retValues[0]) : 0,
                            customName  = _retValues[1]          ?? "",
                            level       = _retValues[2]  != "nil" ? Convert.ToInt32(_retValues[2]) : 0,
                            xp          = _retValues[3]  != "nil" ? Convert.ToInt32(_retValues[3]) : 0,
                            maxXp       = _retValues[4]  != "nil" ? Convert.ToInt32(_retValues[4]) : 0,
                            displayID   = _retValues[5]  != "nil" ? Convert.ToInt32(_retValues[5]) : 0,
                            favorite    = _retValues[6]  != "nil" && ToBoolean(_retValues[6]),
                            petName     = _retValues[7]          ?? "",
                            petIcon     = _retValues[8]          ?? PetConsts.UNKNOWN_ICON,       
                            petType     = _retValues[9]  != "nil" ? Convert.ToInt32(_retValues[9]) : 0,
                            creatureID  = _retValues[10] != "nil" ? Convert.ToInt32(_retValues[10]) : 0,
                            sourceText  = _retValues[11]         ?? "",
                            description = _retValues[12]         ?? "",
                            isWildPet   = _retValues[13] != "nil" && ToBoolean(_retValues[13]),
                            canBattle   = _retValues[14] != "nil" && ToBoolean(_retValues[14]),
                            tradable    = _retValues[15] != "nil" && ToBoolean(_retValues[15]),
                            unique      = _retValues[16] != "nil" && ToBoolean(_retValues[16])
                        };
        }


        /// <summary>
        /// Return Pet info by speciesID
        /// </summary>
        /// <param name="speciesID">(int) speciesID</param>
        /// <returns>[_PetInfo] {(string)petName, (string)petIcon, (int)petType, (int)creatureID, (string)sourceText, (string)description, (bool)isWildPet, (bool)unknown_1, (bool)unknown_2, (bool)unknown_3}</returns>
        /// 
        public static _PetInfo GetPetInfoBySpeciesID(int speciesID)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetPetInfoBySpeciesID({0})", speciesID));
            return new _PetInfo
                        {
                            petName     = _retValues[0]         ?? "",
                            petIcon     = _retValues[1]         ?? PetConsts.UNKNOWN_ICON,
                            petType     = _retValues[2] != "nil" ? Convert.ToInt32(_retValues[2])    : 0,
                            creatureID  = _retValues[3] != "nil" ? Convert.ToInt32(_retValues[3])    : 0,
                            sourceText  = _retValues[4]         ?? "",
                            description = _retValues[5]         ?? "",
                            isWildPet   = _retValues[6] != "nil" && ToBoolean(_retValues[6]),
                            canBattle   = _retValues[7] != "nil" && ToBoolean(_retValues[7]),
                            tradable    = _retValues[8] != "nil" && ToBoolean(_retValues[8]),
                            unique      = _retValues[9] != "nil" && ToBoolean(_retValues[9])
                        };
        }


        /// <summary>
        /// Return loadOut info about PetSlot
        /// </summary>
        /// <param name="louadOutID">(int)loadOutID (1-3)</param>
        /// <returns>[_loadOutInfo] {(string)petGUID, (int)ability1ID, (int)ability2ID, (int)ability3ID, (bool)locked}</returns>
        /// 
        public static _loadOutInfo GetPetLoadOutInfo(int louadOutID)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetPetLoadOutInfo('{0}')", louadOutID));
            return new _loadOutInfo
                       {
                           petGUID      = _retValues[0]         ?? "",
                           ability1ID   = _retValues[1] != "nil" ? Convert.ToInt32(_retValues[1]) : 0,
                           ability2ID   = _retValues[2] != "nil" ? Convert.ToInt32(_retValues[2]) : 0,
                           ability3ID   = _retValues[3] != "nil" ? Convert.ToInt32(_retValues[3]) : 0,
                           locked       = _retValues[4] != "nil" && ToBoolean(_retValues[4])
                       };
        }


        /// <summary>
        /// Returns the index of the currently active sort parameter
        /// </summary>
        /// <returns>(PetSortFlags) sort order</returns>
        /// 
        public static PetConsts.PetSortFlags GetPetSortParameter()
        {
            PetConsts.PetSortFlags _retVal;
            Enum.TryParse(Lua.GetReturnVal<string>("return C_PetJournal.GetPetSortParameter()", 0), true, out _retVal);
            return _retVal;
        }


        /// <summary>
        /// Returns the average level of pets in your battle pet team
        /// </summary>
        /// <returns>(int) level</returns>
        /// 
        public static int GetPetTeamAverageLevel()
        {
            var _retVal = Lua.GetReturnVal<string>("return C_PetJournal.GetPetTeamAverageLevel()", 0);
            return _retVal != "nil" ? Convert.ToInt32(_retVal) : 0;
        }


        /// <summary>
        /// Return Pet stats by GUID
        /// </summary>
        /// <param name="petGUID">(int) petGUID</param>
        /// <returns>[] {(int)health, (int)maxHealth, (int)attack, (int)speed, (int)rarity}</returns>
        /// 
        public static _PetStats GetPetStats(string petGUID)
        {
            var _retValues = Lua.GetReturnValues(string.Format("return C_PetJournal.GetPetStats('{0}')", petGUID));
            return new _PetStats
                       {
                           health    = _retValues[0] != "nil" ? Convert.ToInt32(_retValues[0]) : 0,
                           maxHealth = _retValues[1] != "nil" ? Convert.ToInt32(_retValues[1]) : 0,
                           attack    = _retValues[2] != "nil" ? Convert.ToInt32(_retValues[2]) : 0,
                           speed     = _retValues[3] != "nil" ? Convert.ToInt32(_retValues[3]) : 0,
                           rarity    = _retValues[4] != "nil" ? Convert.ToInt32(_retValues[4]) : 0
                       };
        }


        /// <summary>
        /// Return GUID of currently summoned pet
        /// </summary>
        /// <returns>(string) pet GUID</returns>
        /// 
        public static string GetSummonedPetGUID()
        {
            return Lua.GetReturnVal<string>("return C_PetJournal.GetSummonedPetGUID()", 0);
        }


        /// <summary>
        /// Is finding battles enabled
        /// </summary>
        /// <returns>(bool) enabled</returns>
        /// 
        public static bool IsFindBattleEnabled()
        {
            return ToBoolean(Lua.GetReturnVal<string>("return C_PetJournal.IsFindBattleEnabled()", 0));
        }


        /// <summary>
        /// Return is Journal flag selected
        /// </summary>
        /// <param name="journalFlag">(int) JournalFlag</param>
        /// <returns>(bool) selected</returns>
        /// 
        public static bool IsFlagFiltered(int journalFlag)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.IsFlagFiltered({0})", journalFlag), 0));
        }


        /// <summary>
        /// Is PetJournal unlocked
        /// </summary>
        /// <returns>(bool) unlocked</returns>
        /// 
        public static bool IsJournalUnlocked()
        {
            return ToBoolean(Lua.GetReturnVal<string>("return C_PetJournal.IsJournalUnlocked()", 0));
        }


        /// <summary>
        /// Return is filter selected
        /// </summary>
        /// <param name="sourceFilterID">(int) sourceFilterID</param>
        /// <returns>(bool) selected</returns>
        /// 
        public static bool IsPetSourceFiltered(int sourceFilterID)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.IsPetSourceFiltered({0})", sourceFilterID), 0));
        }


        /// <summary>
        /// Return is type filter selected
        /// </summary>
        /// <param name="typeFilterID">(int) typeFilterID</param>
        /// <returns>(bool) selected</returns>
        /// 
        public static bool IsPetTypeFiltered(int typeFilterID)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.IsPetTypeFiltered({0})", typeFilterID), 0));
        }


        /// <summary>
        /// Is pet can be released
        /// </summary>
        /// <param name="petIndx">(int) pet index</param>
        /// <returns>(bool) pet releasable</returns>
        /// 
        public static bool PetCanBeReleased(int petIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetCanBeReleased({0})", petIndx), 0));
        }


        /// <summary>
        /// Is pet can be place in cage
        /// </summary>
        /// <param name="petIndex">(int) Pet Index</param>
        /// <returns>(bool) cagable</returns>
        /// 
        public static bool PetIsCapturable(int petIndex)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetIsCapturable({0})", petIndex), 0));
        }


        /// <summary>
        /// Return is pet marked as favorite
        /// </summary>
        /// <param name="petGUID">(string) pet GUID</param>
        /// <returns>(bool) favorite</returns>
        /// 
        public static bool PetIsFavorite(int petGUID)
        {
            return ToBoolean(Lua.GetReturnVal<string>(
                string.Format("return C_PetJournal.PetIsFavorite('{0}')", petGUID), 0));
        }


        /// <summary>
        /// Is pet not at full HP
        /// </summary>
        /// <param name="petIndx">(int) pet index</param>
        /// <returns>(bool) hurted</returns>
        /// 
        public static bool PetIsHurt(int petIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetIsHurt({0})", petIndx), 0));
        }


        /// <summary>
        /// Is pet locked
        /// </summary>
        /// <param name="petIndx">(int) pet index</param>
        /// <returns>(bool) is locked</returns>
        /// 
        public static bool PetIsLockedForConvert(int petIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetIsLockedForConvert({0})", petIndx), 0));
        }


        /// <summary>
        /// Is pet revoked
        /// </summary>
        /// <param name="petIndx">(int) pet index</param>
        /// <returns>(bool) revoked</returns>
        /// 
        public static bool PetIsRevoked(int petIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetIsRevoked({0})", petIndx), 0));
        }


        /// <summary>
        /// Is pet in battle slot
        /// </summary>
        /// <param name="petIndx">(int) pet index</param>
        /// <returns>(bool) pet in slot</returns>
        /// 
        public static bool PetIsSlotted(int petIndx)
        {
            return ToBoolean(Lua.GetReturnVal<string>(string.Format("return C_PetJournal.PetIsSlotted({0})", petIndx), 0));
        }


        /// <summary>
        /// Return is pet can be summoned
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// <returns>(bool) summonable</returns>
        /// 
        public static bool PetIsSummonable(string petGUID)
        {
            return ToBoolean(Lua.GetReturnVal<string>(
                string.Format("return C_PetJournal.PetIsSummonable('{0}')", petGUID), 0));
        }


        /// <summary>
        /// Return is pet can be traided
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// <returns>(bool) tradable</returns>
        /// 
        public static bool PetIsTradable(int petGUID)
        {
            return ToBoolean(Lua.GetReturnVal<string>(
                string.Format("return C_PetJournal.PetIsTradable('{0}')", petGUID), 0));
        }


        /// <summary>
        /// Release pet by GUID
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// 
        public static void ReleasePetByID(string petGUID)
        {
            Lua.DoString(string.Format("C_PetJournal.ReleasePetByID('{0}')", petGUID));
        }


        /// <summary>
        /// Set ability to pet in loadOut
        /// </summary>
        /// <param name="petIndx">(int) petIndx</param>
        /// <param name="abilityIndx">(int) abilityIndx</param>
        /// <param name="abilityID">(int) abilityID</param>
        /// 
        public static void SetAbility(int petIndx, int abilityIndx, int abilityID)
        {
            Lua.DoString(string.Format("C_PetJournal.SetAbility({0},{1},{2})", petIndx, abilityIndx, abilityID));
        }


        /// <summary>
        /// Set custom name to pet
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// <param name="name">(string) name - localize filtered</param>
        /// 
        public static void SetCustomName(string petGUID, string name)
        {
            Lua.DoString(string.Format("C_PetJournal.SetCustomName('{0}','{1}')", petGUID, name));
        }


        /// <summary>
        /// Set pet as favorite
        /// </summary>
        /// <param name="petGUID">(string) petGUID</param>
        /// <param name="set">(bool) set/unset</param>
        /// 
        public static void SetFavorite(string petGUID, bool set)
        {
            Lua.DoString(string.Format("C_PetJournal.SetFavorite('{0}',{1})", petGUID, set));
        }


        /// <summary>
        /// Set filter flag
        /// </summary>
        /// <param name="flagID">(int) flagID</param>
        /// <param name="set">(bool) set/unset</param>
        /// 
        public static void SetFlagFilter(int flagID, bool set)
        {
            Lua.DoString(string.Format("C_PetJournal.SetFlagFilter({0},{1})", flagID, set));
        }


        /// <summary>
        /// Set pet into loadOut
        /// </summary>
        /// <param name="loadOutIndx">(int) loadOutIndx</param>
        /// <param name="petGUID">(string) petGUID</param>
        /// 
        public static void SetPetLoadOutInfo(int loadOutIndx, string petGUID)
        {
            Lua.DoString(string.Format("C_PetJournal.SetPetLoadOutInfo({0},'{1}')", loadOutIndx, petGUID));
        }
        public static void SetPetIntoLoadOut(int loadOutIndx, string petGUID)
        {
            SetPetLoadOutInfo(loadOutIndx, petGUID);
        }


        /// <summary>
        /// Set pet source filter
        /// </summary>
        /// <param name="sourceIndx">(int) sourceIndx</param>
        /// <param name="set">(bool) set/unset</param>
        /// 
        public static void SetPetSourceFilter(int sourceIndx, bool set)
        {
            Lua.DoString(string.Format("C_PetJournal.SetPetSourceFilter({0},{1});PetJournal_UpdatePetList();", sourceIndx, set));
        }


        /// <summary>
        /// Set pet type filter
        /// </summary>
        /// <param name="typeIndx">(int) typeIndx</param>
        /// <param name="set">(bool) set/unset</param>
        /// 
        public static void SetPetTypeFilter(int typeIndx, bool set)
        {
            Lua.DoString(string.Format("C_PetJournal.SetPetTypeFilter({0},{1});PetJournal_UpdatePetList();", typeIndx, set));
        }


        /// <summary>
        /// Set text filter 
        /// </summary>
        /// <param name="text">(string) text</param>
        /// 
        public static void SetSearchFilter(string text)
        {
            Lua.DoString( string.Format("C_PetJournal.SetSearchFilter({0})", text) );
        }


        /// <summary>
        /// Changes the battle pet ordering in the pet journal
        /// </summary>
        /// <param name="sortParameter">enum(PetSortFlags) flag</param>
        /// 
        public static void SetSortParameter(PetConsts.PetSortFlags sortParameter)
        {
            Lua.DoString(string.Format("C_PetJournal.SetSortParameter({0}); PetJournal_UpdatePetList()", sortParameter));
        }


        /// <summary>
        /// Summons (or dismisses) a pet
        /// </summary>
        /// <param name="petGUID">(string) pet GUID</param>
        public static void SummonPetByGUID(string petGUID)
        {
            Lua.DoString(string.Format("C_PetJournal.SummonPetByGUID({0})", petGUID));
        }


        /// <summary>
        /// Summons a random battle pet companion
        /// </summary>
        /// <param name="allPets">(bool) true to summon any pet, false to summon one of your favorite pets</param>
        /// 
        public static void SummonRandomPet(bool allPets)
        {
            Lua.DoString(string.Format("C_PetJournal.SummonRandomPet({0})", allPets.ToString()));
        }

        #endregion
    }
}
